<!-- HTML header for doxygen 1.8.10-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="generator" content="Doxygen 1.8.10" />
    <title>ZRDDS: ZRDDS常见问题</title>
    <link href="tabs.css" rel="stylesheet" type="text/css" />
    <script type="text/javascript" src="jquery.js"></script>
    <script type="text/javascript" src="dynsections.js"></script>
    <link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtreedata.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<script type="text/javascript">
  $(document).ready(initResizable);
  $(window).load(resizeHeight);
</script>
    <link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<script type="text/javascript">
  $(document).ready(function() { init_search(); });
</script>
    <link href="doxygen.css" rel="stylesheet" type="text/css" />
    <link href="customdoxygen.css" rel="stylesheet" type="text/css"/>
    <link href="static/css/bootstrap.css" rel="stylesheet" />
    <!-- <link href="static/css/sticky-footer-navbar.css" rel="stylesheet">
    <script type="text/javascript" src="static/js/bootstrap.js"></script> -->
    <script type="text/javascript" src="static/js/doxy-boot.js"></script>
</head>
<body>
    <div id="top">
        <!-- do not remove this div, it is closed by doxygen! -->
        <!-- end header part --><!-- 制作者 Doxygen 1.8.10 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "search",false,'搜索');
</script>
  <div id="navrow1" class="tabs">
    <ul class="tablist">
      <li><a href="index.html"><span>首页</span></a></li>
      <li class="current"><a href="pages.html"><span>相关页面</span></a></li>
      <li><a href="namespaces.html"><span>包</span></a></li>
      <li><a href="annotated.html"><span>类</span></a></li>
      <li><a href="examples.html"><span>示例</span></a></li>
      <li>
        <div id="MSearchBox" class="MSearchBoxInactive">
        <span class="left">
          <img id="MSearchSelect" src="search/mag_sel.png"
               onmouseover="return searchBox.OnSearchSelectShow()"
               onmouseout="return searchBox.OnSearchSelectHide()"
               alt=""/>
          <input type="text" id="MSearchField" value="搜索" accesskey="S"
               onfocus="searchBox.OnSearchFieldFocus(true)" 
               onblur="searchBox.OnSearchFieldFocus(false)" 
               onkeyup="searchBox.OnSearchFieldChange(event)"/>
          </span><span class="right">
            <a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
          </span>
        </div>
      </li>
    </ul>
  </div>
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
  <div id="nav-tree">
    <div id="nav-tree-contents">
      <div id="nav-sync" class="sync"></div>
    </div>
  </div>
  <div id="splitbar" style="-moz-user-select:none;" 
       class="ui-resizable-handle">
  </div>
</div>
<script type="text/javascript">
$(document).ready(function(){initNavTree('faq.html','');});
</script>
<div id="doc-content">
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div class="header">
  <div class="headertitle">
<div class="title">ZRDDS常见问题 </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><h1><a class="anchor" id="support_q"></a>
1.技术支持</h1>
<h2><a class="anchor" id="support_q_1"></a>
1.1.ZRDDS支持哪些操作系统以及编译器？</h2>
<p>　　ZRDDS支持Windows XP及以上，已测试编译器：VS2008、VS2010、VS2012、VS2013、VS2015、MinGW-gcc4.4、MinGW-gcc-5.1.0、MinGW-gcc-6.3.0、Linux2.6及以上，已测试系统Ubuntu14.04、Ubuntu16.04、CentOS7.0 。VxWorks5.5以上，已测试PowerPC架构、MIPS架构、x86架构，国产操作系统方面包括：x86中标麒麟7.0、飞腾银河麒麟4.0、x86翼辉4.7.2、x86以及飞腾的ReWorks。</p>
<h2><a class="anchor" id="support_q_2"></a>
1.2.ZRDDS支持哪些通信协议？</h2>
<p>　　ZRDDS支持UDP、TCP、共享内存、RapidIO、PCIE、40G/100G高速UDP、TCP。</p>
<h2><a class="anchor" id="support_q_3"></a>
1.3.ZRDDS支持哪些工具以及服务？</h2>
<p>　　目前包括：ZRDDS管理监视器工具、系统设计工具、记录与回放工具、PING、SPY工具、持久化服务、WEB服务以及安全服务。</p>
<h1><a class="anchor" id="IDL_q"></a>
2.IDL问题</h1>
<h2><a class="anchor" id="IDL_q_1"></a>
2.1.使用ZRDDS一定需要使用IDL文件，并使用编译器生成类型支持文件吗？</h2>
<p>　　否，ZRDDS提供一系列内置的数据类型及其类型支持文件，这些数据类型包括： #DDS_Char #DDS_Octet #DDS_Boolean #DDS_Short #DDS_UShort #DDS_Long #DDS_ULong #DDS_LongLong #DDS_ULongLong #DDS_Float #DDS_Double #DDS_Bytes #DDS_KeyedBytes #DDS_String #DDS_KeyedString #DDS_ZeroCopyBytes ，使用的步骤与用户自定义类型一致。示例代码如下：</p>
<div class="fragment"><div class="line">DDS::StringTypeSupport::get_instance()-&gt;register_type(dp, NULL);</div>
<div class="line">DDS::Topic* topic = dp-&gt;create_topic(</div>
<div class="line">  <span class="stringliteral">&quot;TestInnerType&quot;</span>, </div>
<div class="line">  DDS::StringTypeSupport::get_instance()-&gt;get_type_name(),</div>
<div class="line">  DDS::TOPIC_QOS_DEFAULT, </div>
<div class="line">  NULL, DDS::STATUS_MASK_NONE);</div>
</div><!-- fragment --><h2><a class="anchor" id="IDL_q_2"></a>
2.2.IDL文件中的字符串类型映射为什么数据结构？</h2>
<p>　　字符串在C与C++中均映射为 #DDS_Char *，在C++中并未映射为std:: string，在Java中映射为 java.lang.String 。</p>
<h2><a class="anchor" id="IDL_q_3"></a>
2.3.IDL文件中的动态数组sequence映射为什么数据结构？</h2>
<p>　　sequence表示动态数组，sequence&lt;T&gt;在ZRDDS中映射为以T为参数的 ZRSequence &lt;T&gt;模板实例化类型，C中包括一系列的支持函数，参见 CoreQosStruct #FooSeq ，C++中包括一些列的成员函数 参见 CoreQosStruct #FooSeq 。</p>
<h1><a class="anchor" id="transport_q"></a>
3.通信问题</h1>
<h2><a class="anchor" id="transport_q_1"></a>
3.1.在Windows上简单的发布/订阅通信不了通常包含哪些原因？</h2>
<p>　　如果通信不了，应依次检查以下因素：</p>
<ul>
<li>网线是否连好？</li>
<li>两个节点是否网络畅通，通常使用ping工具诊断？</li>
<li>是否在同一个局域网？</li>
<li>是否得到ZRDDS的授权（参考安装配置手册.pdf）？</li>
<li>防火墙是否关闭，或者开启时其策略是否允许UDP组播通过？</li>
<li>主题及注册的类型名称是否一致？</li>
<li>是否正确设置监听回调接口及其相关的掩码状态？</li>
</ul>
<h2><a class="anchor" id="transport_q_2"></a>
3.2.在Linux上简单的发布/订阅通信不了通常包含哪些原因？</h2>
<p>　　如果通信不了，应依次检查以下因素：</p>
<ul>
<li>网线是否连好？</li>
<li>两个节点是否网络畅通，通常使用ping工具诊断？</li>
<li>是否在同一个局域网？</li>
<li>是否添加组播路由（<code>sudo route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0(应修改为对应通信的那个接口名称)</code>）?</li>
<li>是否得到ZRDDS的授权（参考安装配置手册.pdf）？</li>
<li>防火墙是否关闭（<code>systemctl stop firewalld.service</code>），或者开启时其策略是否允许UDP组播通过？</li>
<li>主题及注册的类型名称是否一致？</li>
<li>是否正确设置监听回调接口及其相关的掩码状态？</li>
</ul>
<h2><a class="anchor" id="transport_q_3"></a>
3.3.为何使用带有变长成员的数据结构，调用 DataWriter::write 方法发送数据时，程序容易发生崩溃？</h2>
<p>IDL定义如下：</p>
<div class="fragment"><div class="line"><span class="keyword">struct </span>ShapeTypeData</div>
<div class="line">{</div>
<div class="line">    <span class="keywordtype">long</span> id;</div>
<div class="line">    <span class="keywordtype">string</span> extra_mes;</div>
<div class="line">};</div>
</div><!-- fragment --><p>发送代码如下：</p>
<div class="fragment"><div class="line">ShapeTypeData t_data;</div>
<div class="line"><span class="keywordflow">for</span>(<span class="keywordtype">int</span> i=0;i&lt;100;++i)</div>
<div class="line">{</div>
<div class="line">    t_data.id = i</div>
<div class="line">    dw-&gt;write(t_data);</div>
<div class="line">}</div>
</div><!-- fragment --><p>　　在发送数据时，应注意发送数据的初始化（特别是char*类型）。在上述代码中，用户由于未初始化通信数据(t_data)，导致通信数据(t_data)中的extra_mes(char*类型)成员变量为一个野指针，从而在发送数据（调用write方法）的过程中引发了无法预料的问题。 用户可以选择调用DDS提供的ShapeTypeDataInitialize方法对通信数据进行初始化，也可以自行对通信数据初始化。若用户通过ShapeTypeDataInitialize方法对通信数据进行初始化，应在销毁数据时调用ShapeTypeDataFinalize方法。反之，不需要（用户自管理申请的空间）。</p>
<h2><a class="anchor" id="transport_q_4"></a>
3.4.如何避免使用ZRDDS时造成内存泄漏</h2>
<p>IDL定义如下：</p>
<div class="fragment"><div class="line"><span class="keyword">struct </span>ShapeTypeData</div>
<div class="line">{</div>
<div class="line">    <span class="keywordtype">long</span> id;</div>
<div class="line">    <span class="keywordtype">string</span> extra_mes;</div>
<div class="line">};</div>
</div><!-- fragment --><p>发送代码如下：</p>
<div class="fragment"><div class="line">ShapeTypeData t_data;</div>
<div class="line">ShapeTypeDataInitialize(&amp;t_data);</div>
<div class="line">m_data.extra_mes = <span class="stringliteral">&quot;hello world&quot;</span>;</div>
<div class="line"><span class="keywordflow">for</span>(<span class="keywordtype">int</span> i=0; i&lt;10;++i)</div>
<div class="line">{</div>
<div class="line">    dw-&gt;write(t_data);</div>
<div class="line">}</div>
<div class="line">ShapeTypeDataFinalize(&amp;t_data);</div>
</div><!-- fragment --><p>　　用户调用ShapeTypeDataInitialize方法初始化数据后，DDS已为char*类型的成员申请了默认大小的空间（默认大小一般为255，可在通过idl编译器编译生成数据类型文件时修改）。上述代码中，用户对成员变量extra_mes进行了二次赋值，从而导致在ShapeTypeDataInitialize方法中申请的空间无法在调用ShapeTypeDataFinalize方法时释放。该部分赋值正确的写法为：<code>strcpy(m_data.extra_mes, "hello world");</code>。</p>
<h2><a class="anchor" id="transport_q_5"></a>
3.5.在接收DDS数据时，为何在访问接收数据时可能会抛出异常（提示dataSeq[0]的内容为空）？</h2>
<p>　　DataReaderListener不仅仅只会回调通知用户通信数据，还会回调通知用户状态数据（例：已匹配的对端数据写者的下线）。用户应通过SampleInfoSeq对象实例中的valid_data信息判断数据是否有效（即为通信数据），再访问数据。获取并处理数据的正确代码如下：</p>
<div class="fragment"><div class="line"><span class="keyword">class </span>shapeTypeDataListener</div>
<div class="line">{</div>
<div class="line">    <span class="keywordtype">void</span> on_data_available(DataReader *reader)</div>
<div class="line">    {</div>
<div class="line">        ShapeTypeDataReader* _dr = dynamic_case&lt; ShapeTypeDataReader*&gt;(reader);</div>
<div class="line"></div>
<div class="line">        ShapeTypeDataSeq dataSeq;</div>
<div class="line">        SampleInfoSeq infoSeq;</div>
<div class="line">        myMsgReader-&gt;take(dataSeq, infoSeq, MAX_INT32_VALUE, ANY_SAMPLE_STATE, ANY_VIEW_STATE, ANY_INSTANCE_STATE);</div>
<div class="line">        <span class="keywordflow">for</span>(<span class="keywordtype">int</span> i=0;i&lt;infoSeq.length();++i)</div>
<div class="line">        {</div>
<div class="line">            <span class="keywordflow">if</span>(infoSeq[i].valid_data)</div>
<div class="line">            {</div>
<div class="line">                printf(“this is is %d”, dataSeq[i].<span class="keywordtype">id</span>);</div>
<div class="line">            }</div>
<div class="line">        }</div>
<div class="line">    }</div>
<div class="line">}</div>
</div><!-- fragment --><h2><a class="anchor" id="transport_q_6"></a>
3.6.sequence数据结构在使用时，长度有限制吗？</h2>
<p>　　在使用Sequence类型变量时，可以在IDL文件中自定义其长度，例：<code>sequence&lt;int, 128&gt; int_seq</code> ，也可以使用默认的长度，即不定义长度（此时长度默认为255,使用编译器参数<code>-sequence_bound</code>修改），例：sequence&lt;int&gt; int_seq，也可以通过编译器选项<code>-enable_unbounded</code>中设置使用无限长度。</p>
<h2><a class="anchor" id="transport_q_7"></a>
3.7.DDS在以太网UDP/TCP传输中，最大传输数据长度为多少？</h2>
<p>　　DDS最大传输数据长度与当前使用的通信协议和数据类型有关。DDS传输过程使用的数据类型根据是否为零拷贝可分为非零拷贝数据类型和零拷贝数据类型，零拷贝数据类型即为 #DDS_ZeroCopyBytes ，除此以外的都为非零拷贝数据类型，包括DDS其他内置数据类型和用户通过IDL自定义的数据类型。非零拷贝数据类型以DDS内置的 #DDS_Bytes （无符号一字节整型sequence）为例进行说明。</p>
<p>　　以下为默认配置下UDP/TCP能传输的最大数据长度，以及目前DDS能支持的最大传输长度和对应的配置。</p>
<table class="doxtable">
<tr>
<td colspan="2"></td><td>默认配置 </td><td>UDP下最大传输配置 </td><td colspan="2">TCP下最大传输配置  </td></tr>
<tr>
<td rowspan="7">配置 </td><td>fragSize </td><td>4MB </td><td>4MB </td><td>4MB </td><td>4MB  </td></tr>
<tr>
<td>fragMaxSize(UDP) </td><td>65408B </td><td>65408B </td><td>65408B </td><td>65408B  </td></tr>
<tr>
<td>fragMaxSize(TCP) </td><td>2100000B </td><td>2100000B </td><td>2100000B </td><td class="qos_change">2^31-8B  </td></tr>
<tr>
<td>fragMaxNum </td><td>4160 </td><td>4160 </td><td>4160 </td><td>4160  </td></tr>
<tr>
<td>recvBufLen(UDP) </td><td>0B </td><td class="qos_change">65504B </td><td>0B </td><td>0B  </td></tr>
<tr>
<td>recvBufLen(TCP) </td><td>0B </td><td>0B </td><td class="qos_change">2^31-4B </td><td>0B  </td></tr>
<tr>
<td>reservedLen </td><td>1024B </td><td>1024B </td><td class="qos_change">0B </td><td class="qos_change">0B  </td></tr>
<tr>
<td rowspan="2">UDP最大传输长度 </td><td>零拷贝 </td><td>65360B≈63KB </td><td class="qos_change">65452B≈63KB </td><td>65360B≈63KB </td><td>65360B≈63KB  </td></tr>
<tr>
<td>非零拷贝 </td><td>(65408-512)*4160-8B≈257MB </td><td>(65408-512)*4160-8B≈257MB </td><td>(65408-512)*4160-8B≈257MB </td><td>(65408-512)*4160-8B≈257MB  </td></tr>
<tr>
<td rowspan="2">TCP最大传输长度 </td><td>零拷贝 </td><td>2099952B≈2MB </td><td>2099952B≈2MB </td><td class="qos_change">2^31-4-52B≈2GB </td><td class="qos_change">2^31-4-52B≈2GB  </td></tr>
<tr>
<td>非零拷贝 </td><td>2^32-4-8B≈4GB </td><td>2^32-4-8B≈4GB </td><td>2^32-4-8B≈4GB </td><td>2^32-4-8B≈4GB  </td></tr>
</table>
<p>　　表中用颜色标记的项目，表示的是达到目前支持的最大传输长度需要修改的配置，以及修改之后相对默认配置有所变化的最大传输长度。每个配置及其说明如下。</p>
<table class="doxtable">
<tr>
<th>配置名 </th><th>对应DDS配置项 </th><th>说明  </th></tr>
<tr>
<td>fragSize </td><td>sysctl.dw.statistic.fragment_length </td><td>数据读者发送数据时进行分片的大小 </td></tr>
<tr>
<td>fragMaxSize(UDP) </td><td>sysctl.global.net.zrnet_ipv4_udp_max_packet_length </td><td>使用UDP协议时的单个分片大小，由用户确保收发两边保持一致 </td></tr>
<tr>
<td>fragMaxSize(TCP) </td><td>sysctl.global.net.zrnet_ipv4_tcp_max_packet_length </td><td>使用TCP协议时的单个分片大小，由用户确保收发两边保持一致 </td></tr>
<tr>
<td>fragMaxNum </td><td>无 </td><td>数据读者支持的最大分片个数，目前固定为4160 </td></tr>
<tr>
<td>recvBufLen(UDP) </td><td>DDS_DomainParticipantQos.receiver_thread_config.receive_buffer_length </td><td>接收缓冲区大小，使用UDP协议 </td></tr>
<tr>
<td>recvBufLen(TCP) </td><td>DDS_DomainParticipantQos.receiver_thread_config.receive_buffer_length </td><td>接收缓冲区大小，使用TCP协议 </td></tr>
<tr>
<td>reservedLen </td><td>DDS_ZeroCopyBytes.reservedLength </td><td>为底层预留的协议头空间，发送时申请空间需要加上这个长度，所以可能会影响最大传输长度 </td></tr>
</table>
<p>　　根据以上配置计算最大传输长度的方式如下，单位为B，字节。</p>
<table class="doxtable">
<tr>
<td colspan="3">场景 </td><td colspan="2">最大传输长度  </td></tr>
<tr>
<td rowspan="3">UDP </td><td rowspan="2">零拷贝 </td><td>reservedLen == 0 </td><td>min(fragMaxSize(UDP)+4-52, 2^31-1-reservedLen)  </td></tr>
<tr>
<td>reservedLen &gt; 0 </td><td>min(recvBufLen(UDP)-52, 65504-52, 2^31-1-reservedLen)  </td></tr>
<tr>
<td colspan="2">非零拷贝 </td><td>min(fragSize, fragMaxSize(UDP))*fragMaxNum-8  </td></tr>
<tr>
<td rowspan="3">TCP </td><td rowspan="2">零拷贝 </td><td>reservedLen == 0 </td><td>min(fragMaxSize(TCP)+4-52, 2^31-1-reservedLen)  </td></tr>
<tr>
<td>reservedLen &gt; 0 </td><td>min(recvBufLen(TCP)-52, 2^31-4-52, 2^31-1-reservedLen)  </td></tr>
<tr>
<td colspan="2">非零拷贝 </td><td>min(min(fragSize, fragMaxSize(UDP))*fragMaxNum-8, 2^32-4-8)  </td></tr>
</table>
<p>　　UDP和TCP协议下最大传输长度具体说明如下。</p>
<h3><a class="anchor" id="transport_q_7_UDP"></a>
3.7.1.UDP</h3>
<p>　　UDP协议本身最大支持长度为2^16-1B，除去IP头（20B）和UDP头（8B），UDP协议本身理论可传输的最大长度为65507B。</p><ul>
<li>使用非零拷贝 #DDS_Bytes 时，DDS内部会进行分片，UDP协议默认会以65408B大小（最大可设置为65408B)为一个分片，传输最大长度就受分片总个数限制。目前DDS分片总个数最大为4160个，每个分片中预设512B作为DDS报文头序列化的空间，因此非零拷贝下最大传输数据长度为<b>(65408-512)*4160-8B</b>，约<b>257MB</b>。</li>
<li>使用零拷贝 #DDS_ZeroCopyBytes 时，DDS不会进行分片，内部会对数据进行4字节对齐，因此DDS能够发送的最大长度为65504B，大于默认的接收缓冲区大小65408B，通过修改 #DDS_DomainParticipantQos 中接收缓冲区大小（ #DDS_ReceiverThreadConfigQosPolicy ）为65504B才能正常接收。去除DDS报文头大小后，零拷贝下最大传输数据长度为<b>65452B(65504-52B)</b>。</li>
</ul>
<h3><a class="anchor" id="transport_q_7_TCP"></a>
3.7.2.TCP</h3>
<p>　　TCP协议本身理论上没有对数据长度进行限制。</p><ul>
<li>使用非零拷贝 #DDS_Bytes 时，DDS内部会进行分片，TCP协议默认会以2100000B大小为一个分片，按照分片总个数最大为4160个算出来的最大包长会超过无符号32位整型最大值，因此非零拷贝下最大传输数据长度为<b>2^32-4-8B</b>，约<b>4GB</b>。</li>
<li>使用零拷贝 #DDS_ZeroCopyBytes 时，DDS不会进行分片，DDS接收缓冲区的大小限制了最大传输数据长度，默认配置下为2100000+4B，约2MB；DDS接收缓冲区大小可通过设置 #DDS_ReceiverThreadConfigQosPolicy 中接收缓冲区大小（receive_buffer_length）或者当前使用协议的最大分片大小（sysctl.global.net.zrnet_ipv4_tcp_max_packet_length）进行修改（receive_buffer_length为0时以最大分片大小为准）。DDS发送时可发送的最大发送长度为2^31-4B（4字节对齐），去掉DDS报文头后用户数据最大可发送长度为2^31-4-52B。通过设置接收端域参与者的接收缓冲区大小为2^31-4B（receive_buffer_length最大可设置2^31-1B），或者设置TCP最大分片大小为2^31-8B（sysctl.global.net.zrnet_ipv4_tcp_max_packet_length最大可设置2^31-8B），通信能达到零拷贝下最大传输数据长度<b>2^31-4-52B</b>，约<b>2GB</b>。</li>
</ul>
<h2><a class="anchor" id="transport_q_8"></a>
3.8.DDS使用零拷贝数据类型和非零拷贝数据类型进行通信的区别</h2>
<p>　　DDS传输过程使用的数据类型根据是否为零拷贝可分为非零拷贝数据类型和零拷贝数据类型，零拷贝数据类型即为 #DDS_ZeroCopyBytes ，除此以外的都为非零拷贝数据类型，包括DDS其他内置数据类型和用户通过IDL自定义的数据类型。非零拷贝数据类型以DDS内置的 #DDS_Bytes （无符号一字节整型sequence）为例进行说明。</p>
<p>　　DDS传输过程如<a href="#figure-1">图1</a>所示，零拷贝 #DDS_ZeroCopyBytes 和 非零拷贝 #DDS_Bytes 在用户通信接口调用方式和支持的通信协议范围方面是一致的，两者存在差异的方面主要体现在使用规则和传输性能上。</p>
<p><a class="anchor" id="figure-1"></a> </p><div class="image">
<img src="ddstransport.png" alt="ddstransport.png"/>
<div class="caption">
图1. DDS通信示意图</div></div>
 <h3><a class="anchor" id="transport_q_8_rules"></a>
3.8.1.使用规则</h3>
<p>　　零拷贝 #DDS_ZeroCopyBytes 和 非零拷贝 #DDS_Bytes 在使用规则上主要有以下几个区别。</p><ul>
<li>样本构造不同，零拷贝 #DDS_ZeroCopyBytes 和 非零拷贝 #DDS_Bytes 属于不同的数据类型，有各自的数据结构，及样本构造方法；</li>
<li>数据队列不同，非零拷贝 #DDS_Bytes 通过设置数据队列的长度可以修改通信过程中发送、接收数据的最大缓存个数，允许数据在队列中暂存，而零拷贝 #DDS_ZeroCopyBytes 队列长度为一，收到一包数据后用户必须尽快取出(take函数) ，避免被下一包数据替换；</li>
<li>可靠模式支持不同，在非可靠网络中，非零拷贝 #DDS_Bytes 可以通过设置 #DDS_ReliabilityQosPolicy 等QoS策略使用DDS可靠配置来保证一定程度的可靠性，而零拷贝 #DDS_ZeroCopyBytes 不支持DDS可靠配置，此时的可靠性由网络协议本身决定；</li>
<li>数据包长度限制不同，非零拷贝 #DDS_Bytes 会进行数据分片，在不同通信协议下有不同的分片大小，当数据包大小大于分片大小后，会按照对应的分片大小来拆分数据包，而零拷贝 #DDS_ZeroCopyBytes 不会进行数据分片，相当于只能有一个分片，数据包支持的最大长度由分片大小决定。DDS在以太网UDP/TCP传输中，两种数据类型支持的最大传输数据长度参见<a class="el" href="faq.html#transport_q_7">3.7.DDS在以太网UDP/TCP传输中，最大传输数据长度为多少？</a></li>
</ul>
<h3><a class="anchor" id="transport_q_8_tp"></a>
3.8.2.传输速度</h3>
<p>　　零拷贝 #DDS_ZeroCopyBytes 在通信过程的序列化、反序列化过程中通过减少数据拷贝的次数，来提升使用零拷贝 #DDS_ZeroCopyBytes 进行通信时的传输速度，因此在通信协议自身保证可靠的前提下，建议优先使用零拷贝 #DDS_ZeroCopyBytes 进行通信。 </p>
</div></div><!-- contents -->
</div><!-- doc-content -->
<!-- HTML footer for doxygen 1.8.10-->
<!-- start footer part -->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
  <ul>
    <li class="footer">
      <a href="http://www.zrtechnology.com">&copy; Copyright (c) 2018 ZhenRong Technology, Inc. All rights reserved.</a>
    </li>
  </ul>
</div>
</body>
</html>
